
package com.wwy.monitor.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wwy.monitor.common.MessageException;
import com.wwy.monitor.common.MonitorConstant;
import okhttp3.*;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMethod;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author tianquan.ld
 * @version V1.0
 * <p>Description: okHttp Util</p>
 * @date 2019-11-01 16:02
 */
public class OkHttpUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(OkHttpUtil.class);
    /**
     * HTTP_CLIENT.
     */
    private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder().connectTimeout(15000, TimeUnit.MILLISECONDS)
            .readTimeout(30000, TimeUnit.MILLISECONDS)
            .build();
    /**
     * æåç .
     */
    private static int SUCCESS_STATUS_CODE = 200;
    private static Integer CONTENT_TYPE_JSON = 1;
    private static Integer CONTENT_TYPE_FORMDATA = 2;

    /**
     * è¯·æ±æäº¤
     *
     * @param host   ä¸»æº
     * @param url    è·¯å¾
     * @param port   ç«¯å£å·ï¼æ²¡æåé»è®¤80
     * @param method è¯·æ±æ¹æ³
     * @param param  è¯·æ±参数ï¼å¦æä¸ºget deleteï¼åä¸ºqueryStringæ¹å¼ï¼å¦æä¸ºpost putï¼åä¸ºrequestBodyæäº¤æ¹å¼ï¼å¥åé½æ¯json
     * @param header è¯·æ±å¤´ jsonç±»å
     * @return ååºå®ä½
     * @throws Exception
     */
    public static Response submitForResponse(String host, Integer port, String url, String method, String header, String param, boolean isDomain, Integer contentType) throws Exception {
        return getResponse(initRequest(host, port, url, method, header, param, isDomain, contentType));
    }

    /**
     * è¯·æ±æäº¤
     *
     * @param host     ä¸»æº
     * @param url      è·¯å¾
     * @param port     ç«¯å£å·ï¼æ²¡æåé»è®¤80
     * @param method   è¯·æ±æ¹æ³
     * @param param    è¯·æ±参数ï¼å¦æä¸ºget deleteï¼åä¸ºqueryStringæ¹å¼ï¼å¦æä¸ºpost putï¼åä¸ºrequestBodyæäº¤æ¹å¼ï¼å¥åé½æ¯json
     * @param header   è¯·æ±å¤´ jsonç±»å
     * @param isDomain æ¯å¦æ¯ååè¯·æ±
     * @return ååºå­ç¬¦ä¸²
     * @throws Exception
     */
    public static String submitForString(String host, Integer port, String url, String method, String header, String param, boolean isDomain, Integer contentType)
            throws Exception {
        return getResponseString(initRequest(host, port, url, method, header, param, isDomain, contentType));
    }

    public static Request initRequest(String host, Integer port, String url, String method, String header, String param, boolean isDomain, Integer contentType) {
// åºç¡校验
        validateRequest(host, url, method, header, param);
        if (port == null) {
            port = MonitorConstant.DEFAULT_HTTP_PORT;
        }
// æ¼æ¥è®¿é®å°å
        host = host.endsWith("/") ? host.substring(0, host.length() - 1) : host;
        url = url.startsWith("/") ? url.substring(1) : url;
        String fullUrl = String.format("%s:%s/%s", host, port, url);
        if (isDomain) {
            fullUrl = String.format("%s/%s", host, url);
        }
        Request.Builder requestBuilder = new Request.Builder();
        if (StringUtils.isNotEmpty(header)) {
// æ·»å è¯·æ±å¤´
            Map<String, String> headerMap = JSON.parseObject(header, Map.class);
            if (MapUtils.isNotEmpty(headerMap)) {
                headerMap.entrySet().stream().forEach((item) -> {
                    requestBuilder.addHeader(item.getKey(), String.valueOf(item.getValue()));
                });
            }
        }
// åå§åè¯·æ±
        Request request = null;
        if (RequestMethod.GET.name().equalsIgnoreCase(method)) {
            request = requestBuilder.url(fullUrl + convertToQueryString(param)).get().build();
        } else if (RequestMethod.POST.name().equalsIgnoreCase(method)) {
            RequestBody requestBody = convertToRequestBody(param, contentType);
            request = requestBuilder.url(fullUrl).post(requestBody).build();
        } else if (RequestMethod.PUT.name().equalsIgnoreCase(method)) {
            RequestBody requestBody = convertToRequestBody(param, contentType);
            request = requestBuilder.url(fullUrl).put(requestBody).build();
        } else if (RequestMethod.DELETE.name().equalsIgnoreCase(method)) {
            request = requestBuilder.url(fullUrl + convertToQueryString(param)).delete().build();
        } else {
            throw new MessageException("ä¸æ¯æçè¯·æ±æ¹æ³ï¼" + method);
        }
        return request;
    }

    /**
     * 校验è¯·æ±
     *
     * @param host
     * @param url
     * @param header
     * @param param
     */
    private static void validateRequest(String host, String url, String method, String header, String param) {
        if (StringUtils.isBlank(host)) {
            throw new MessageException("è¯·æ±ä¸»æºä¸è½ä¸ºç©º");
        }
        if (StringUtils.isBlank(url)) {
            throw new MessageException("è¯·æ±è·¯å¾ä¸è½ä¸ºç©º");
        }
        boolean methodFlag = FormatUtil.validateHttpMethod(method);
        if (!methodFlag) {
            throw new MessageException("ä¸æ¯æçè¯·æ±æ¹æ³:" + method);
        }
        if (StringUtils.isNotEmpty(param)) {
            boolean paramJsonFlag = FormatUtil.validateJson(param);
            if (!paramJsonFlag) {
                throw new MessageException("è¯·æ±参数ä»æ¯æJSONæ ¼å¼");
            }
        }
        if (StringUtils.isNotEmpty(header)) {
            boolean headerJsonFlag = FormatUtil.validateJson(header);
            if (!headerJsonFlag) {
                throw new MessageException("è¯·æ±å¤´ä»æ¯æJSONæ ¼å¼");
            }
        }
    }

    /**
     * è½¬æ¢ä¸ºæ¥è¯¢å­ç¬¦ä¸²
     *
     * @param param
     * @return
     */
    private static String convertToQueryString(String param) {
        StringBuilder builder = new StringBuilder("?");
        if (StringUtils.isBlank(param)) {
            return "";
        }
        Map<String, String> paramMap = JSON.parseObject(param, Map.class);
        if (MapUtils.isNotEmpty(paramMap)) {
            paramMap.entrySet().stream().forEach((item) -> {
                builder.append(item.getKey()).append("=").append(item.getValue()).append("&");
            });
        }
        String result = builder.toString();
        return result.substring(0, result.length() - 1);
    }

    /**
     * è½¬æ¢ä¸ºrequestBody
     *
     * @param param
     * @return
     */
    private static RequestBody convertToRequestBody(String param, Integer contentType) {
        RequestBody requestBody = null;
        if (StringUtils.isNotBlank(param)) {
            if (null != contentType) {
//è¯·æ±ç±»åä¸º application/json
                if (CONTENT_TYPE_JSON.equals(contentType)) {
                    requestBody = RequestBody.create(MediaType.parse(MonitorConstant.MEDIA_TYPE_JSON), param);
                } else if (CONTENT_TYPE_FORMDATA.equals(contentType)) {
                    JSONObject json = JSONObject.parseObject(param);
                    FormBody.Builder builder = new FormBody.Builder();
                    for (String name : json.keySet()) {
                        String value = json.getString(name);
                        builder.add(name, value);
                    }
                    requestBody = builder.build();
                } else {
                    throw new MessageException("ä¸æ¯æçpostæ¹æ³åå®¹ç¼ç ç±»åï¼" + contentType);
                }
            } else {
                throw new MessageException("httpè¯·æ±postæ¹æ³åå®¹ç¼ç ç±»åä¸ºç©º");
            }
        }
        return requestBody;
    }

    /**
     * å¤çè¯·æ±
     *
     * @param request
     * @return
     */
    private static String getResponseString(Request request) {
        Response resp = null;
        String res = null;
        try {
            resp = exec(request);
            if (resp != null && resp.isSuccessful()) {
                res = resp.body().string();
            }
        } catch (Exception e) {
            LOGGER.error("è·åååºå¤±è´¥ï¼åå ï¼{}", e.getMessage());
        } finally {
            if (resp != null) {
                resp.body().close();
            }
        }
        return res;
    }

    /**
     * å¤çè¯·æ±
     *
     * @param request
     * @return
     */
    private static Response getResponse(Request request) {
        Response resp = null;
        try {
            return exec(request);
        } catch (Exception e) {
            LOGGER.error("è·åååºå¤±è´¥ï¼åå ï¼{}", e.getMessage());
            return null;
        } finally {
            if (resp != null) {
                resp.body().close();
            }
        }
    }

    public static Response exec(Request request) throws Exception {
        return HTTP_CLIENT.newCall(request).execute();
    }
}